/*!
* @file    main.c
* @version v1.0
* @date    2018-02-05
* @author  苏勇 suyong_yq@126.com
* @brief   LPC SmartCar整车单元模块验证工程
*          在本工程中，所有功能模块在均被初始化后验证了功能，从而确保了所有的模块可以同时工作
*          本工程也是也是一个参考编程的模板，用户可以根据具体应用场景对本工程代码裁剪
*/
#include "app_inc.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
/*
* 选择单元测试项目：
* - 按排列顺序第一个非0测试用例有效
* - 后续使能任务无效
*/
#define APP_CFG_ENABLE_SERVO_TEST   0  /* PASS. */
#define APP_CFG_ENABLE_MOTOR_L_TEST 1  /* PASS. */
#define APP_CFG_ENABLE_MOTOR_R_TEST 0  /* PASS. */
#define APP_CFG_ENABLE_ENC_L_TEST   1  /* PASS. */
#define APP_CFG_ENABLE_ENC_R_TEST   0  /* PASS. */
#define APP_CFG_ENABLE_CAMERA_TEST  0  /* PASS. */

/*******************************************************************************
 * Variables
 ******************************************************************************/
char gAppPrintfBuffer[256]; /* OLED显示屏打印输出的格式化缓冲区 */
uint32_t gAppServoDuty;     /* 当前舵机的控制输出占空比，对应舵机转向角度 */
int32_t gAppMotorLDuty;     /* 当前左驱动电机的控制PWM输出占空比，对应电机转速 */
bool bAppMotorLForward;     /* 当前左驱动电机的控制方向 */
int32_t gAppEncLSpeed;      /* 当前左电机编码器测速值 */
int32_t gAppMotorRDuty;     /* 当前右驱动电机的控制PWM输出占空比，对应电机转速 */
bool bAppMotorRForward;     /* 当前右驱动电机的控制方向 */
int32_t gAppEncRSpeed;      /* 当前右电机编码器测速值 */

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void App_BootClockRUN(void);
void App_Tick_PeriodicalCallback(void);
void App_OLED_ShowCamera(void);
void App_ProcessImage(void);

/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief Main function
 */
int main(void)
{
    /* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_BootClockRUN();
    App_BootClockRUN(); /* Enable the clocks additionally not in BOARD_BootClockRUN(). */

    /* Initialize debug console. */
    BOARD_InitDebugConsole(); /* Flexcomm0 - UART0, 115200. */

    PRINTF("\r\nLPCSmartCar AllInOne.\r\n");
    PRINTF("build time: %s, %s\r\n", __TIME__, __DATE__);

    /* OLED显示屏 */
    OLED_Init();
    OLED_PrintReset();
    OLED_PrintStr("LPCSmartCar\r\n");

    /* 按键与延时组件 */
    Tick_Init(200UL); /* 5ms per tick. */
    BTN_Init();
    Tick_InstallPeriodicalCallback(1U, App_Tick_PeriodicalCallback);

    /* 初始化舵机控制 */
    OLED_PrintStr("Servo ...\r\n");
    Servo_Init(SERVO_PWM_DUTY_MID);

    while (1)
    {

    	
    }

#if 0
#if APP_CFG_ENABLE_SERVO_TEST /* 测试舵机 */
    //OLED_PrintStr("K1 to change duty\r\n");
    gAppServoDuty = SERVO_PWM_DUTY_MID;
    while (1)
    {
        //BTN_WaitBlocking(1U);
        //Tick_DelayBlocking(5U); /* 100ms */
        GETCHAR();
        sprintf(gAppPrintfBuffer, "duty: %d\r\n", gAppServoDuty);
        OLED_PrintStr(gAppPrintfBuffer);
        Servo_SetPosition(gAppServoDuty);
        gAppServoDuty += 100U;
              if (gAppServoDuty > SERVO_PWM_DUTY_MAX)
        {
            gAppServoDuty = SERVO_PWM_DUTY_MIN;
        }
    }
#endif /* APP_CFG_ENABLE_SERVO_TEST */

    /* 初始化前进电机控制 */
    OLED_PrintStr("Motor L ...\r\n");
    MotorL_InitDriver();
#if APP_CFG_ENABLE_MOTOR_L_TEST /* 测试左电机 */
    gAppMotorLDuty = 0;
    bAppMotorLForward = true;
    while (1)
    {
        GETCHAR();

        MotorL_SetSpeed(gAppMotorLDuty);
        PRINTF("gAppMotorLDuty: %d\r\n", gAppMotorLDuty);

        if (bAppMotorLForward)
        {
            gAppMotorLDuty++;
            if (gAppMotorLDuty >= MOTOR_L_SPEED_PWM_DUTY_LIMIT)
            {
                bAppMotorLForward = false;
            }
        }
        else
        {
            gAppMotorLDuty--;
            if (gAppMotorLDuty <= -MOTOR_L_SPEED_PWM_DUTY_LIMIT)
            {
                bAppMotorLForward = true;
            }
        }
    }
#endif /* APP_CFG_ENABLE_MOTOR_L_TEST */

    OLED_PrintStr("Motor R ...\r\n");
    MotorR_InitDriver();
#if APP_CFG_ENABLE_MOTOR_R_TEST /* 测试右电机 */
    gAppMotorRDuty = 0;
    bAppMotorRForward = true;
    while (1)
    {
        GETCHAR();

        MotorR_SetSpeed(gAppMotorRDuty);
        PRINTF("gAppMotorRDuty: %d\r\n", gAppMotorRDuty);

        if (bAppMotorRForward)
        {
            gAppMotorRDuty++;
            if (gAppMotorRDuty >= MOTOR_R_SPEED_PWM_DUTY_LIMIT)
            {
                bAppMotorRForward = false;
            }
        }
        else
        {
            gAppMotorRDuty--;
            if (gAppMotorRDuty <= -MOTOR_R_SPEED_PWM_DUTY_LIMIT)
            {
                bAppMotorRForward = true;
            }
        }
    }
#endif

    OLED_PrintStr("Enc L ...\r\n");
    MotorL_InitEncoder();
#if APP_CFG_ENABLE_ENC_L_TEST /* 启用左编码器测试 */
    while (1)
    {
        GETCHAR();
        gAppEncLSpeed = MotorL_GetSpeed();
        PRINTF("gAppEncLSpeed: %d\r\n", gAppEncLSpeed);
    }
#endif /* APP_CFG_ENABLE_ENC_L_TEST */

    OLED_PrintStr("Enc R ...\r\n");
    MotorR_InitEncoder();
#if APP_CFG_ENABLE_ENC_R_TEST /* 启用左编码器测试 */
    while (1)
    {
        GETCHAR();
        gAppEncRSpeed = MotorR_GetSpeed();
        PRINTF("gAppEncRSpeed: %d\r\n", gAppEncRSpeed);
    }
#endif /* APP_CFG_ENABLE_ENC_R_TEST */



    /* 初始化摄像头传感器 */
    OLED_PrintStr("Camera ...\r\n");
    Camera_Init();
#if APP_CFG_ENABLE_CAMERA_TEST

    while (1)
    {
        Camera_StartCapture();
        App_ProcessImage();
        App_OLED_ShowCamera();
    }
#endif /* APP_CFG_ENABLE_CAMERA_TEST */
#endif


    OLED_PrintStr("GameOver\r\n");
    PRINTF("GameOver\r\n");
    while (1)
    {
    }
}

/* 启用在BOARD_BootClockRUN()函数中未启用的时钟
* 这些模块多半也是自定义驱动。SDK提供的驱动内部会开关外设访问时钟
*/
void App_BootClockRUN(void)
{
    CLOCK_EnableClock(kCLOCK_Gpio0);
    CLOCK_EnableClock(kCLOCK_Gpio1);
    CLOCK_EnableClock(kCLOCK_InputMux);
    CLOCK_EnableClock(kCLOCK_Sct0);
    CLOCK_EnableClock(kCLOCK_Dma);
}

/* 由Systick周期调用的回调函数 */
void App_Tick_PeriodicalCallback(void)
{
    BTN_WaitBlockingHook();
}

/* DMA传输完成中断 */
void DMA0_IRQHandler(void)
{
    uint32_t flags = DMA_GetChannelsOnInterruptA(DMA0);

    /* 处理摄像头数据搬运事件 */
    if (0U != (flags & (1U << CAMERA_DMA_CHANNEL_IDX)))
    {
        Camera_DmaIRQHandlerHook();
    }
    DMA_ClearFlagsOnInterruptA(DMA0, flags);
}

/* 实现隔点采样后，将从摄像头采集的320x240数据压缩成OLED可显示的128*64个点
 ******** 横向5个像素，纵向4个像素合并成一个数据，最后空出来来4个像素行
 * 横向2个像素，纵向4个像素合并成一个数据，剩下的留空
 */

uint8_t gOledDisplayBuffer[OLED_LINE_COUNT_MAX][OLED_ROW_COUNT_MAX];

void App_ProcessImage(void)
{
    uint32_t line, row, idx;
    uint8_t thresh = Image_GetThreshold_OTSU((uint8_t *)gCameraPixelData, CAMERA_PIXELS_PER_FRAME);
    //uint32_t leftEdgePos, rightEdgePos;
    //bool bRet;

    for (line = 0U; line < CAMERA_LINES_PER_FRAME; line++) /* 遍历每一行 */
    {
        /* 二值化 */
        for (row = 0U; row < CAMERA_PIXELS_PER_LINE2; row++)
        {
            idx = line*CAMERA_PIXELS_PER_LINE2 + row;
            if (gCameraPixelData[idx] > thresh)
            {
              gCameraPixelData[idx] = 1U;
            }
            else
            {
              gCameraPixelData[idx] = 0U;
            }
        }
#if 0
        /* 进行边界检测 */
        bRet = Image_GetEdgePixels( (uint8_t *)gCameraPixelData+line*CAMERA_PIXELS_PER_LINE2,
                        CAMERA_PIXELS_PER_LINE2, &leftEdgePos, &rightEdgePos);
        /* 重建新的像素数据，仅显示边界 */
        for (row = 0U; row < CAMERA_PIXELS_PER_LINE2; row++)
        {
            idx = line*CAMERA_PIXELS_PER_LINE2 + row;
            if (bRet & ((row == leftEdgePos) || (row == rightEdgePos)))
            {
                gCameraPixelData[idx] = 1U;
            }
            else
            {
                gCameraPixelData[idx] = 0U;
            }
        }
#endif
    }
}

void App_CompressShowData(void)
{
    uint32_t line, row; /* OLED显示的行和列编号 */
    uint32_t bIdx;
    uint32_t camDatAcc; /* 抽取要显示的点 */
    uint8_t  dat;

    //uint8_t thresh = Image_GetThreshold_OTSU(gCameraPixelData, CAMERA_PIXELS_PER_FRAME);

    for (line = 0U; line < OLED_LINE_COUNT_MAX-1U; line++)
    {
        for (row = 0U; row < (OLED_ROW_COUNT_MAX); row++)
        {
            dat = 0U;
            for (bIdx = 0U; bIdx < 8U; bIdx++)
            {

                camDatAcc = gCameraPixelData[  2U * (line * 8U + bIdx) * CAMERA_PIXELS_PER_LINE2 /* 寻址行 */
                                             + 2U * row]; /* 寻址列 */
                /* 显示已经二值化的像素信息 */
                if (camDatAcc == 1U)
                {
                    //dat |= (1U << (7U-bIdx));
                    dat |= (1U << bIdx);
                }
            }
            gOledDisplayBuffer[line][/* OLED_ROW_COUNT_MAX-1U-*/row] = dat;
        }
    }
}

void App_OLED_ShowCamera(void)
{
    uint32_t line;

    App_CompressShowData();
    for (line = 0U; line < OLED_LINE_COUNT_MAX; line++)
    {
        OLED_WriteLine(line, 0U, gOledDisplayBuffer[line], OLED_ROW_COUNT_MAX);
    }
}

/* EOF. */
